package com.jerome.rmi;

import com.jerome.rmi.enums.OperatorEnum;
import com.jerome.rmi.util.MathUtil;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.List;

/**
 * Calculator Implementation
 *
 * @author jerome
 * @date 2023/7/28
 */
public class CalculatorImplementation extends UnicastRemoteObject implements Calculator {
    /**
     * Just the stack information of the calculator
     */
    private List<Integer> stack = new ArrayList<Integer>();
    /**
     * test num
     * ignore it
     */
    private int num = 0;

    protected CalculatorImplementation() throws RemoteException {
        super();
    }

    /**
     * This is a test ,
     * Use synchronized to prevent concurrent operations on data
     * please ignore it
     * @param name any string
     * @return test string
     * @throws RemoteException
     */
    @Deprecated
    public synchronized String test(String name) throws RemoteException {
        num++;
        String s = Thread.currentThread().getId() + ":" + name + ":" + num;
        System.out.println(s);
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return s;
    }

    /**
     * This method will pop the top of the stack and return it to the client.
     *
     * @return the top of the stack ,if stack is empty ,return 0
     */
    public synchronized int pop() throws RemoteException {
        if (isEmpty()) {
            return 0;
        }
        return stack.remove(stack.size() - 1);
    }

    /**
     * This method will return true if the stack is empty, false otherwise
     *
     * @return true (is empty) and false (is not empty)
     * @throws RemoteException
     */
    public synchronized boolean isEmpty() throws RemoteException {
        return stack.isEmpty();
    }

    /**
     * This method will wait millis milliseconds before carrying out the pop operation as above.
     *
     * @param millis wait millis milliseconds
     * @return value
     * @throws RemoteException
     */
    public synchronized int delayPop(int millis) throws RemoteException, InterruptedException {
        Thread.sleep(millis);
        return pop();
    }

    /**
     * This method will take val and push it on to the top of the stack
     *
     * @param val take it to stack
     * @throws RemoteException
     */
    public synchronized void pushValue(int val) throws RemoteException {
        stack.add(val);
    }

    /**
     * This method wi push a String containing an operator (" min" "max "cm""gcd") to the stack
     * which wil cause the server to *POP ALL* the values on the stack
     *
     * @param operator (" min" "max "lcm""gcd")
     * @throws RemoteException
     */
    public synchronized void pushOperation(String operator) throws RemoteException {
        OperatorEnum operatorEnum = OperatorEnum.getByName(operator);
        if (operatorEnum == null) {
            throw new IllegalArgumentException("invalid operation");
        }
        switch (operatorEnum) {
            case MIN:
                int min = MathUtil.findMin(stack);
                stack.clear();
                stack.add(min);
                break;
            case MAX:
                int max = MathUtil.findMax(stack);
                stack.clear();
                stack.add(max);
                break;
            case LCM:
                int lcm = MathUtil.findLCM(stack);
                stack.clear();
                stack.add(lcm);
                break;
            case GCD:
                int gcd = MathUtil.findGCD(stack);
                stack.clear();
                stack.add(gcd);
                break;
            default:
                break;
        }
    }
}
